package com.info33.platform.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.info33.platform.common.constant.TableConstant;
import com.info33.platform.common.exception.TransactionalException;
import com.info33.platform.common.mvc.vo.Result;
import com.info33.platform.system.dao.*;
import com.info33.platform.system.dto.SysTenantMenuDTO;
import com.info33.platform.system.entity.SysMenu;
import com.info33.platform.system.entity.SysMenuUser;
import com.info33.platform.system.entity.SysPost;
import com.info33.platform.system.entity.SysTenantMenu;
import com.info33.platform.system.service.SysTenantMenuService;
import com.info33.platform.system.vo.SysMenuListVO;
import com.info33.platform.system.vo.SysTenantMenuDetailVO;
import com.info33.platform.system.vo.SysTenantMenuVO;
import com.info33.platform.system.vo.SysUserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@Service
public class SysTenantMenuServiceImpl extends ServiceImpl<SysTenantMenuDao, SysTenantMenu> implements SysTenantMenuService {

    @Autowired
    SysTenantMenuDao sysTenantMenuDao;
    @Autowired
    SysMenuDao sysMenuDao;
    @Autowired
    SysMenuUserDao sysMenuUserDao;
    @Autowired
    SysPostDao sysPostDao;
    @Autowired
    private SysShortcutMenuDao sysShortcutMenuDao;

    @Override
    public SysMenuListVO pageMenuList(Long tenantId, Long pid, int pageNum, int pageSize) {
        SysMenuListVO sysMenuListVO = new SysMenuListVO();
        // 获取父级菜单
        SysTenantMenu parentSysMenu = new SysTenantMenu();
        if (0L == pid) {
            parentSysMenu.setId(0L);
            parentSysMenu.setName("一级菜单");
        } else {
            parentSysMenu = sysTenantMenuDao.selectParentMenu(pid);
        }
        sysMenuListVO.setParentSysMenu(parentSysMenu);
        // 分页获取菜单列表
        IPage<SysTenantMenu> page = new Page<SysTenantMenu>(pageNum, pageSize);
        IPage<SysTenantMenu> menuList = sysTenantMenuDao.pageMenuList(tenantId, pid, page);
        sysMenuListVO.setMenuList(menuList);
        return sysMenuListVO;
    }

    @Override
    public List<SysTenantMenuVO> pcMenuTree(SysUserVO currentUser) {
        return menuTree(sysTenantMenuDao.pcMenu(currentUser), 0L);
    }

    public List<SysTenantMenuVO> menuTree(List<SysTenantMenuVO> sysMenuVOList, Long pid) {
        List<SysTenantMenuVO> collect = sysMenuVOList.stream().filter(l -> l.getPid().equals(pid)).collect(Collectors.toList());
        collect.forEach(l -> l.setTenantMenuVOList(menuTree(sysMenuVOList, l.getMenuId())));
        return collect;
    }

    @Override
    public SysTenantMenuDetailVO getMenuDetail(Long id) {
        SysTenantMenuDetailVO menuDetailVO = new SysTenantMenuDetailVO();
        SysTenantMenu sysMenu = sysTenantMenuDao.selectById(id);
        menuDetailVO.setMenu(sysMenu);
        // 获取父级菜单
        SysTenantMenu parentSysMenu = new SysTenantMenu();
        if (0L == sysMenu.getPid()) {
            parentSysMenu.setId(0L);
            parentSysMenu.setName("一级菜单");
        } else {
            parentSysMenu = sysTenantMenuDao.selectOne(new QueryWrapper<SysTenantMenu>().eq("menu_id", sysMenu.getPid())
                    .eq(TableConstant.TENANT_ID, sysMenu.getTenantId()));
        }
        menuDetailVO.setParentMenu(parentSysMenu);
        return menuDetailVO;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, Error.class})
    public Result<?> saveMenu(Long tenantId, SysTenantMenuDTO sysTenantMenuDTO) {
        //获取路由，并校验路由是否存在
        if (!StringUtils.isEmpty(sysTenantMenuDTO.getAction())) {
            SysTenantMenu menu = sysTenantMenuDao.selectOne(new QueryWrapper<SysTenantMenu>()
                    .eq("action", sysTenantMenuDTO.getAction()).eq(TableConstant.TENANT_ID, tenantId));
            if (menu != null) {
                return Result.error("路由已存在");
            }
        }
        SysTenantMenu parentMenu = sysTenantMenuDao.selectById(sysTenantMenuDTO.getPid());
        //添加sys_menu
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(sysTenantMenuDTO, sysMenu);
        sysMenu.setPid(parentMenu == null ? 0 : parentMenu.getMenuId());
        if (sysMenuDao.insert(sysMenu) == 1) {
            //添加sys_tenant_menu
            SysTenantMenu sysTenantMenu = new SysTenantMenu();
            BeanUtils.copyProperties(sysTenantMenuDTO, sysTenantMenu);
            sysTenantMenu.setMenuId(sysMenu.getId());
            sysTenantMenu.setPid(sysMenu.getPid());
            if (sysTenantMenuDao.insert(sysTenantMenu) == 1) {
                // 默认给admin岗位下发
                SysMenuUser sysMenuUser = new SysMenuUser();
                sysMenuUser.setType(2);
                sysMenuUser.setMenuId(sysTenantMenu.getId());
                SysPost sysPost = sysPostDao.selectOne(new QueryWrapper<SysPost>().eq(TableConstant.TENANT_ID, tenantId)
                        .eq("indexes", TableConstant.NEW_TENANT_INDEX));
                sysMenuUser.setPostId(sysPost.getId());
                if (sysMenuUserDao.insert(sysMenuUser) == 1) {
                    return Result.ok();
                }
            }

        }
        throw new TransactionalException();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, Error.class})
    public Result<?> updateMenu(Long tenantId, SysTenantMenu sysTenantMenu) {
        if (!StringUtils.isEmpty(sysTenantMenu.getAction())) {
            SysTenantMenu menu = sysTenantMenuDao.selectOne(new QueryWrapper<SysTenantMenu>()
                    .eq("action", sysTenantMenu.getAction()).eq(TableConstant.TENANT_ID, tenantId)
                    .ne(TableConstant.ID, sysTenantMenu.getId()));
            if (menu != null) {
                return Result.error("路由已存在");
            }
        }
        //编辑全部菜单信息的需要同时更新sys_menu和sys_tenant_menu
        if (sysTenantMenu.getEdit()) {
            SysMenu sysMenu = sysMenuDao.selectById(sysTenantMenu.getMenuId());
            Integer version = sysMenu.getVersion();
            BeanUtils.copyProperties(sysTenantMenu, sysMenu);
            sysMenu.setId(sysTenantMenu.getMenuId());
            sysMenu.setVersion(version);
            if (sysMenuDao.updateById(sysMenu) == 1) {
                sysTenantMenu.setNewName(sysMenu.getName());
                sysTenantMenu.setVersion(null);
                sysTenantMenu.setTenantId(null);
                sysTenantMenu.setEdit(null);
                if (sysTenantMenuDao.update(sysTenantMenu, new UpdateWrapper<SysTenantMenu>()
                        .eq("menu_id", sysTenantMenu.getMenuId())) > 0) {
                    return Result.ok();
                }
            }
        } else {
            if (sysTenantMenuDao.updateById(sysTenantMenu) == 1) {
                return Result.ok();
            }
        }
        throw new TransactionalException();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, Error.class})
    public Result<?> removeMenu(Long tenantId, List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Result.error("请选择要删除的菜单");
        }
        List<Long> menuIds = new ArrayList<Long>();
        for (Long id : ids) {
            SysTenantMenu sysTenantMenu = sysTenantMenuDao.selectById(id);
            if (sysTenantMenu == null) {
                return Result.error("数据不存在");
            }
            Integer menuCount = sysTenantMenuDao.selectCount(new QueryWrapper<SysTenantMenu>().eq(TableConstant.PID, sysTenantMenu.getMenuId())
                    .eq(TableConstant.TENANT_ID, tenantId));
            if (menuCount > 0) {
                return Result.error("菜单“" + sysTenantMenu.getName() + "”存在子菜单，不能删除");
            }
            if (sysTenantMenu.getEdit()) {
                //已下发菜单不能删除
                List<SysTenantMenu> tenantMenuList = sysTenantMenuDao.selectList(new QueryWrapper<SysTenantMenu>()
                        .eq("menu_id", sysTenantMenu.getMenuId()).ne(TableConstant.TENANT_ID, tenantId));
                if (!CollectionUtils.isEmpty(tenantMenuList)) {
                    return Result.error("菜单“" + sysTenantMenu.getName() + "”已下发，不能删除");
                }
                menuIds.add(sysTenantMenu.getMenuId());
            }
        }
        //删除对应分配权限
        sysMenuUserDao.deleteByMenuId(ids);
        if (!CollectionUtils.isEmpty(menuIds)) {
            //删除菜单
            sysMenuDao.deleteBatchIds(menuIds);
        }
        //删除对应快捷菜单
        sysShortcutMenuDao.deleteByMenuId(ids);
        return sysTenantMenuDao.deleteBatchIds(ids) > 0 ? Result.ok() : Result.error();
    }

    @Override
    public List<SysTenantMenuVO> getAllMenuTree(Long tenantId) {
        return menuTree(sysTenantMenuDao.getAllMenu(tenantId), 0L);
    }

    @Override
    public SysTenantMenuVO getMenutreeById(Long id, SysUserVO sysCurrentUser) {
        List<SysTenantMenuVO> menuVOList = sysTenantMenuDao.pcMenu(sysCurrentUser);
        SysTenantMenu sysTenantMenu = sysTenantMenuDao.selectById(id);

        SysTenantMenuVO tenantMenuVO = new SysTenantMenuVO();
        BeanUtils.copyProperties(sysTenantMenu, tenantMenuVO);
        SysTenantMenuVO sysTenantMenuVO = getParentMenu(menuVOList, tenantMenuVO);

        List<SysTenantMenuVO> menuTree = menuTree(menuVOList, sysTenantMenuVO.getMenuId());
        sysTenantMenuVO.setTenantMenuVOList(menuTree);
        return sysTenantMenuVO;
    }

    public SysTenantMenuVO getParentMenu(List<SysTenantMenuVO> menuVOList, SysTenantMenuVO sysTenantMenuVO) {
        if (sysTenantMenuVO.getPid() == 0) {
            return sysTenantMenuVO;
        }

        SysTenantMenuVO sysTenantMenu = menuVOList.stream().filter(
                i -> Objects.equals(i.getMenuId(), sysTenantMenuVO.getPid())
        ).findFirst().get();

        return getParentMenu(menuVOList, sysTenantMenu);
    }

    @Override
    public List<SysTenantMenuVO> getButtonMenuList(String action, SysUserVO currentUser) {
        return sysTenantMenuDao.getButtonMenuList(action, currentUser);
    }

    @Override
    public List<SysTenantMenuVO> treeByUser(SysTenantMenuDTO dto, SysUserVO currentUser) {
        return menuTree(sysTenantMenuDao.listByUser(currentUser), ObjectUtils.isEmpty(dto.getId()) ? 0L : dto.getId());
    }

}